﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using SPFarmDiscovery.SPObjects;
using System.IO;

namespace SPFarmDiscovery
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				if (args.Length == 2)
				{
					Uri uri = new Uri(args[0].ToString());
					string url = uri.ToString();
					string mode = args[1].ToString();
					switch (mode)
					{
						case "WebApplication":
							using (SPSite site = new SPSite(url))
							{
								SPWebApplication webApp = site.WebApplication;
								WriteFile(BuildWebApplication(webApp).ToXml(true));
							}
							break;
						case "SiteCollection":
							using (SPSite site = new SPSite(url))
							{
								WriteFile(BuildSiteCollection(site).ToXml(true));
							}
							break;
						case "Web":
							using (SPSite site = new SPSite(url))
							{
								string relativeWebUrl = "";
								if (site.Url != url) // NOT Root Web
									relativeWebUrl = url.Substring(site.Url.Length + 1);
								using (SPWeb web = site.OpenWeb(relativeWebUrl))
								{
									WriteFile(BuildWebsXml(web).ToXml(true));
								}
							}
							break;
						default:
							throw new Exception("ERROR: specified mode, " + args[1].ToString() + " is not allowed. Enter either 'WebApplication', 'SiteCollection', or 'Web'");
					}
				}
				else
				{ // export farm

					Farm farm = new Farm(0, 0, 0, 0, 0, new List<WebApplication>());
					SPWebServiceCollection svcs = new SPWebServiceCollection(SPFarm.Local);
					foreach (SPWebService svc in svcs)
					{
						foreach (SPWebApplication webApp in svc.WebApplications)
						{
							WebApplication app = BuildWebApplication(webApp);
							farm.WebApplications.Add(app);
							farm.SizeInMB += app.SizeInMB;
							farm.NumberOfWebApplications += 1;
							farm.NumberOfSiteCollections += app.NumberOfSiteCollections;
							farm.NumberOfWebs += app.NumberOfWebs;
							farm.NumberOfLists += app.NumberOfLists;
						}
					}
					WriteFile(farm.ToXml(true));
				}
			}
			catch (Exception e)
			{
				Console.WriteLine(e.Message);
				Console.ReadKey();
			}
		}

		private static WebApplication BuildWebApplication(SPWebApplication webApp)
		{
			SPAlternateUrlCollection urls = webApp.AlternateUrls;
			string url = urls[0].Uri.ToString();
			WebApplication app = new WebApplication(url, 0, 0, 0, 0, new List<SiteCollection>());

			foreach (SPSite siteCollection in webApp.Sites)
			{
				SiteCollection aSite = BuildSiteCollection(siteCollection);
				app.SiteCollections.Add(aSite);
				app.SizeInMB += aSite.SizeInMB;
				app.NumberOfSiteCollections += 1;
				app.NumberOfLists += aSite.NumberOfLists;
				app.NumberOfWebs += aSite.NumberOfWebs;
			}
			return app;
		}

		private static SiteCollection BuildSiteCollection(SPSite siteCollection)
		{
			Web rootWeb = BuildWebsXml(siteCollection.RootWeb);
			SiteCollection aSite = new SiteCollection(rootWeb);
			return aSite;
		}

		private static void WriteFile(string p)
		{
			StreamWriter stream = new StreamWriter("farm.xml", false, Encoding.Default, p.Length + 1);
			stream.WriteLine(p);
			stream.Close();
		}

		private static Web BuildWebsXml(SPWeb web)
		{
			string url = web.Url;
			string title = web.Title;

			double size = CalculateWebSize(web);
			double totalSize = size;
			
			int subWebCount = web.Webs.Count;
			int totalSubWebCount = subWebCount;

			int listCount = web.Lists.Count;
			int totalListCount = listCount;

			List<Web> subWebs = new List<Web>();

			if (web.Webs.Count > 0)
			{
				foreach (SPWeb subWeb in web.Webs)
				{
					Web sub = BuildWebsXml(subWeb);
					totalSize += sub.TotalSizeInMB;
					totalSubWebCount += sub.TotalNumberOfSubWebs;
					totalListCount += sub.TotalNumberOfLists;
					subWebs.Add(sub);
				}
			}

			Web Web = new Web(
				url, title,
				Math.Round(size, 3), Math.Round(totalSize, 3),
				subWebCount, totalSubWebCount,
				listCount, totalListCount,
				subWebs);
			return Web;
		}

		private static double CalculateWebSize(SPWeb web)
		{
			double size = 0;
			size += CalculateFolderSize(web.RootFolder);
			return size;
		}



		private static double CalculateFolderSize(SPFolder folder)
		{
			double size = 0;
			foreach (SPFile file in folder.Files)
			{
				size += (double)file.Length / 1000000;
			}
			if (folder.SubFolders.Count > 0)
			{
				foreach (SPFolder subFolder in folder.SubFolders)
				{
					size += CalculateFolderSize(subFolder);
				}
			}
			return size;
		}
	}
}